#include "project.h"
#include "head.h"
#include <sys/ioctl.h>

#define SERIAL_ADDR 0xfcc9
#define FIRMWARE_ADDR 0x84b8
#define TMP_ADDR 0xe3
#define HUM_ADDR 0xe5
#define GET_SERIAL _IOR('g', 0, int)
#define GET_FIRMWARE _IOR('g', 1, int)
#define GET_TMP _IOR('g', 2, int)
#define GET_HUM _IOR('g', 3, int)

// 显示数字的哪个板子
#define SEG_WHICH _IOW('k', 0, int)
#define SEG_DAT _IOW('k', 1, int)
/*读取消息线程*/
void *msgget_thread(void *argv)
{
	while (1)
	{
		/*读取消息队列*/
		memset(&msg, 0, sizeof(Msg_t));
		printf("--等待读取消息线程\n");
		//   msg.type =-3  即 接收   1 2 3 这三个的内容
		//   0  接收里面的第一个消息  同时系统将 msg.type设置成接收到的  数字
		//   正数   接收指定消息
		// 一直报错 先把读取消息这里写死  debug
		msgrcv(msqid, &msg, sizeof(Msg_t) - sizeof(long), -3, 0);
		// msgrcv(msqid, &msg, sizeof(Msg_t) - sizeof(long), 1, 0);
		printf("--读取消息成功  type【%d】\n", msg.mtype);
		/*区分消息类型 根据消息类型创建功能线程处理事件*/
		switch (msg.mtype)
		{
		case 1:
			/*创建环境信息线程*/
			memset(&env_msg, 0, sizeof(Msg_t));
			env_msg = msg;
			pthread_create(&env_tid, NULL, env_thread, (void *)&env_msg);
			pthread_detach(env_tid);
			break;
		case 2:
			printf("----进入了第二个case里面去\n");
			/*创建阈值设置线程*/
			memset(&limit_msg, 0, sizeof(Msg_t));
			limit_msg = msg;
			// 创建线程  ？？？   第一个没有传参  第二个自己写传参
			// pthread_create(&limit_tid, NULL, limit_thread, NULL);
			pthread_create(&limit_tid, NULL, limit_thread, (void *)&limit_msg);
			printf("----pthread_create 创建线程  传参为 函数 limit_thread 阈值函数 返回 值 limit_tid 【%d】用作后续杀死线程使用\n", limit_tid);
			// 设置线程为 分离状态  线程创建默认是  结合 状态
			// 结合状态在结束之后 需要手动回收 但是分离状态则会自动回收
			pthread_detach(limit_tid);
			printf("%s %s %d \n", __FILE__, __func__, __LINE__);
			break;
		case 3:
			/*创建设备控制线程*/
			memset(&dev_msg, 0, sizeof(Msg_t));
			dev_msg = msg;
			pthread_create(&dev_tid, NULL, dev_thread, (void *)&dev_msg);
			pthread_detach(dev_tid);
			break;
		default:
			break;
		}
	}
}

/*环境信息线程   同时顺带 设置  spi 显示屏幕 */
void *env_thread(void *argv)
{
	printf("%s %s %d \n", __FILE__, __func__, __LINE__);
	Msg_t *msg = (Msg_t *)argv;
	printf("拿到的消息为 【type %d】【】\n", msg->mtype);
	printf("%s %s %d \n", __FILE__, __func__, __LINE__);
	/*读取设备数据*/
	if (1)
	{
		int fd;
		int serial, firmware, tmp, hum;
		float rtmp, rhum;
		if ((fd = open("/dev/si7006", O_RDWR)) == -1)
			printf("open error");

		ioctl(fd, GET_SERIAL, &serial);
		ioctl(fd, GET_FIRMWARE, &firmware);
		// printf("serial = %#x,firmware=%#x\n", serial, firmware);
		for (size_t i = 0; i < 1; i++)
		{
			ioctl(fd, GET_TMP, &tmp);
			ioctl(fd, GET_HUM, &hum);

			rtmp = 175.72 * tmp / 65536 - 46.85;
			rhum = 125 * hum / 65536.0 - 6;

			printf("rtmp温度 = %.2f", rtmp);
			global_wendu = rtmp;

			// fprintf(cgiOut, "<br>\n");
			printf("rhum湿度 = %.2f\n", rhum);
			global_shidu = rhum;
			// fprintf(cgiOut, "<br>\n");
			// usleep(100000);
		}
		close(fd);
	}

	printf("%s %s %d \n", __FILE__, __func__, __LINE__);
	// sleep(5);
	/*封装消息*/
	msg->mtype = 10;
	msg->env.hume = global_shidu;
	msg->env.temp = global_wendu;
	/*发送消息*/
	msgsnd(msqid, msg, sizeof(Msg_t) - sizeof(long), 0);
	/*线程退出*/
	pthread_exit(NULL);
}

/*阈值设置线程*/
void *limit_thread(void *argv)
{
	Msg_t *msg = (Msg_t *)argv;
	/*为主线程参考变量赋值*/
	/*封装消息*/
	/*发送消息*/
	/*线程退出*/

	// 这个内容更新  全局  温度 和湿度  和 设置的阈值进行对比 如果不对就让 spi亮
	if (1)
	{
		int fd;
		int serial, firmware, tmp, hum;
		float rtmp, rhum;
		if ((fd = open("/dev/si7006", O_RDWR)) == -1)
			printf("open error");

		ioctl(fd, GET_SERIAL, &serial);
		ioctl(fd, GET_FIRMWARE, &firmware);
		// printf("serial = %#x,firmware=%#x\n", serial, firmware);
		for (size_t i = 0; i < 1; i++)
		{
			ioctl(fd, GET_TMP, &tmp);
			ioctl(fd, GET_HUM, &hum);

			rtmp = 175.72 * tmp / 65536 - 46.85;
			rhum = 125 * hum / 65536.0 - 6;

			printf("rtmp温度 = %.2f", rtmp);
			global_wendu = rtmp;

			// fprintf(cgiOut, "<br>\n");
			printf("rhum湿度 = %.2f\n", rhum);
			global_shidu = rhum;
			// fprintf(cgiOut, "<br>\n");
			// usleep(100000);
		}
		close(fd);
	}

	// 展示信息  printf
	if (1)
	{
		printf("本地内容为");
		printf("---limit线程里面拿到的  信息结构体里面的东西type 【%d】  \n", msg->mtype);
		printf("---拿到的具体数据为hun_down【%d】【%d】iull_down【%d】【%d】temp_down【%f】【%f】",
			   msg->limit.hume_down,
			   msg->limit.hume_up,
			   msg->limit.iull_down,
			   msg->limit.iull_up,
			   msg->limit.temp_down,
			   msg->limit.temp_up);
	}

	printf("全局变量内容为 -- 温度%f  湿度%f \n", global_wendu, global_shidu);
	limit_t_up = msg->limit.temp_up;
	limit_t_down = msg->limit.temp_down;
	limit_h_up = msg->limit.hume_up;
	limit_h_down = msg->limit.hume_down; // limit_h_down 和   global_shidu对比
	limit_i_up = msg->limit.iull_up;	 // 这个是光照不看这个东西
	limit_i_down = msg->limit.iull_down;
	printf("拿到的 cgi阈值为 limit_t_up %f   limit_t_down %f \n", limit_t_up, limit_t_down);
	int fla_lim = 0;
	if (limit_t_up > global_wendu & limit_t_down < global_wendu)
	{
		printf("温度可以再合理区间\n");
	}
	else
	{
		printf("温度不正确\n");
		fla_lim = fla_lim + 1;
	}

	if (limit_h_up > global_shidu & limit_h_down < global_shidu)
	{
		printf("湿度可以再合理区间\n");
	}
	else
	{
		printf("湿度不正确不在合理的区间\n");
		fla_lim = fla_lim + 1;
	}
	if (fla_lim == 0)
	{
		msg->dev.beep = 1;
		spi_fla = 1;
	}
	else
	{
		msg->dev.beep = 0;
		spi_fla = 0;
	}
	printf("本地阈值设置完成  返回设置完成的消息结构体\n");
	printf("本地阈值设置完成当前阈值 limit_t_up (temp_up)【%f】  limit_i_up (iull_up)【%d】\n ", limit_t_up, limit_i_up);

	printf("组装返回的信息结构体\n");

	// msqid

	msg->mtype = 20;
	msg->limit.hume_down = 0;
	printf("msg->limit.hume_down  【%d】\n", msg->limit.hume_down);
	msgsnd(msqid, msg, MSGSIZE, 0);
	printf("返回的信息结构体发送了\n");
	// float limit_t_up;
	// float limit_t_down;
	// unsigned char limit_h_up;
	// unsigned char limit_h_down;
	// unsigned short limit_i_up;
	// unsigned short limit_i_down;

	// .hume_down = 39,
	//                  .hume_up = 24,
	//                  .iull_down = 23,
	//                  .iull_up = 25,
	//                  .temp_down = 33,
	//                  .temp_up = 43
	printf("---进行处理之后后面需要进行 返回值的操作\n");

	// 自己额外添加内容  使用 哪个屏幕显示数字  spi 显示这个 每次请求环境信息
	if (1)
	{
		printf(" 自己额外添加内容  使用 哪个屏幕显示数字\n");
		int which = 0;
		int data = 0;
		int fd;
		fd = open("/dev/m74hc595", O_RDWR);
		if (fd < 0)
		{
			printf("open error");
			// return -1;
		}
		ioctl(fd, SEG_WHICH, 4);

		if (spi_fla == 0)
		{
			// 这个是设置  spi管子显示这个东西
			ioctl(fd, SEG_DAT, 8);
			// spi_fla = 1;
		}
		else
		{
			// 这个 是设置灯管不显示任何东西
			ioctl(fd, SEG_DAT, 99);
			// spi_fla = 0;
		}
		close(fd);
	}
}

// 这个还是有 bug但是这个有问题  先不搞了  tudo
void *beep_thread(void *argv)
{
	int value;
	int fd;
	if ((fd = open("/dev/beeper_driver", O_RDWR)) < 0)
	{
		perror("open error");
		return -1;
	}

	// 程序执行主逻辑
	for (size_t i = 0; i < 20;)
	{
		int tmp_fla = beep_fla;
		if (beep_fla == 1)
		{
			printf("beep_thread 线程里面执行程序 beep_fla %d \n", beep_fla);
			value = 2000;
			write(fd, &value, sizeof(value));
			sleep(1);

			value = 0;
			write(fd, &value, sizeof(value));
			sleep(1);
		}
		else
		{
			sleep(1);
		}
	}
	close(fd);
}

void *led_thread(void *argv)
{

	// 这个写入  0，1  就是开发板子 点亮和熄灭这个东西
	// 驱动就不动了 能用就行 这个接口也已经测试好了  led的这个就算是弄好了
	// 下面弄另一个 驱动  和测试  使用驱动的  test.c

	int value;
	int fd;
	char zz[100] = "";
	zz[0] = 0;
	if ((fd = open("/dev/myleds", O_RDWR)) == -1)
		PRINT_ERR("open error");
	for (size_t i = 0; i < 19999;)
	{
		int tmp_fla = beep_fla;
		if (beep_fla == 1)
		{
			printf("led_thread 线程里面执行程序 beep_fla %d \n", beep_fla);
			zz[0] = 0;
			write(fd, zz, sizeof(zz));
			sleep(1);
			zz[0] = 1;
			write(fd, zz, sizeof(zz));
			sleep(1);
			// value = 2000;
			// write(fd, &value, sizeof(value));
		}
		sleep(1);
	}

	close(fd);
}

/*设备控制线程*/
void *dev_thread(void *argv)
{
	printf("%s %s %d \n", __FILE__, __func__, __LINE__);

	Msg_t *msg = (Msg_t *)argv;
	printf("拿到的消息为 【type %d】【】\n", msg->mtype);
	printf("拿到的消息为 【FAN  %c】【】\n", msg->dev.fan);
	printf("拿到的消息为 【LED  %c】【】\n", msg->dev.led);
	printf("拿到的消息为 【BEEP %c】【】\n", msg->dev.beep);

	// 对 驱动里面写入0 进行 操作 关闭
	if (msg->dev.led == '0')
	{
		printf("对led进行设置   000 灭掉\n");
		int fd;
		char zz[100] = {};
		zz[0] = 0;
		if ((fd = open("/dev/myleds", O_RDWR)) == -1)
			printf("open error");

		write(fd, zz, sizeof(zz));
		close(fd);
	}

	// 对 驱动里面写入1 进行 操作 开启
	if (msg->dev.led == '1')
	{
		printf("对led进行设置   111 亮\n");

		int fd;
		char zz[100] = {};
		zz[0] = 1;
		if ((fd = open("/dev/myleds", O_RDWR)) == -1)
			printf("open error");
		write(fd, zz, sizeof(zz));
		close(fd);
	}

	// 这个只能再额外开一个线程 给蜂鸣器  不然随着这个结束就不行了
	if (msg->dev.beep == '0')
	{
		beep_fla = 0;
	}

	if (msg->dev.beep == '1')
	{
		beep_fla = 1;
	}

	if (msg->dev.fan == '0')
	{

		int value;
		int fd;
		if ((fd = open("/dev/fan_driver", O_RDWR)) < 0)
		{
			perror("open error");
			return -1;
		}
		// 这个传值控制 风扇 开关  0 关  1 开
		ioctl(fd, 0);
		close(fd);
	}

	if (msg->dev.fan == '1')
	{
		int value;
		int fd;
		if ((fd = open("/dev/fan_driver", O_RDWR)) < 0)
		{
			perror("open error");
			return -1;
		}
		// 这个传值控制 风扇 开关  0 关  1 开
		ioctl(fd, 1);
		close(fd);
	}
	msg->mtype = 30;
	msg->env.hume = global_shidu;
	msg->env.temp = global_wendu;
	/*发送消息   返回消息  解析  第一个beep 里面是成功与否  1 成功 0 失败  */
	msg->dev.beep = '1';
	printf("服务器设置beep为1 代表成功（若是0 则为失败） 【%c】\n", msg->dev.beep);
	printf("服务器发送 【type %d】的消息给网页【】\n", msg->mtype);
	if (1)
	{
		msgsnd(msqid, msg, sizeof(Msg_t) - sizeof(long), 0);
	}
}

/*设备初始化*/
int dev_init(void)
{
	/*建议在主进程中打开设备文件  此函数实现可以忽略*/
}

/*消息队列初始化*/
int msgqueue_init(void)
{
	/*获取 key*/
	key = ftok(MSGPATH, 'a');
	if (-1 == key)
	{
		puts("申请 key 错误");
		return -1;
	}
	/*获取 msqid*/
	msqid = msgget(key, IPC_CREAT | 0666);
	printf("    %s 创建的消息队列信息 【%p】 ", __FILE__, key);

	if (-1 == msqid)
	{
		puts("创建消息队列失败");
		return -1;
	}
	/*返回 成功标识 0*/
	return 0;
}

/*线程初始化*/
int thread_init(void)
{

	// 创建蜂鸣器线程

	if ((errno = pthread_create(&beep_tid, NULL, beep_thread, NULL)) != 0)
	{
		PRINT_ERR("pthread_create error");
	}

	if ((errno = pthread_create(&beep_tid, NULL, led_thread, NULL)) != 0)
		PRINT_ERR("pthread_create error");

	/*创建消息读取线程*/
	if (0 == pthread_create(&tid, NULL, msgget_thread, NULL))
	{
		return 0;
	}
	else
	{
		puts("创建线程失败");
		return -1;
	}
}
